﻿using System;
using System.Collections.Generic;
using System.Text;

namespace MLForgeSharp.Models.SupervisedLearningModels.Linear
{
    /// <summary>
    /// 线性判别分析模型
    /// </summary>
    public class LDAModel
    {
        private double[] weights; // 模型权重
        private double bias; // 偏置项

        public LDAModel()
        {
            weights = null;
            bias = 0.0;
        }

        // 计算均值向量
        private double[] ComputeMean(double[][] data)
        {
            int numFeatures = data[0].Length;
            double[] mean = new double[numFeatures];

            foreach (double[] sample in data)
            {
                for (int i = 0; i < numFeatures; i++)
                {
                    mean[i] += sample[i];
                }
            }

            for (int i = 0; i < numFeatures; i++)
            {
                mean[i] /= data.Length;
            }

            return mean;
        }

        // 计算类内散度矩阵
        private double[,] ComputeWithinClassScatter(double[][] data, double[] mean)
        {
            int numFeatures = data[0].Length;
            double[,] scatter = new double[numFeatures, numFeatures];

            foreach (double[] sample in data)
            {
                for (int i = 0; i < numFeatures; i++)
                {
                    for (int j = 0; j < numFeatures; j++)
                    {
                        scatter[i, j] += (sample[i] - mean[i]) * (sample[j] - mean[j]);
                    }
                }
            }

            return scatter;
        }

        // 计算类间散度矩阵
        private double[,] ComputeBetweenClassScatter(double[] mean1, double[] mean2)
        {
            int numFeatures = mean1.Length;
            double[,] scatter = new double[numFeatures, numFeatures];

            for (int i = 0; i < numFeatures; i++)
            {
                for (int j = 0; j < numFeatures; j++)
                {
                    scatter[i, j] = (mean1[i] - mean2[i]) * (mean1[j] - mean2[j]);
                }
            }

            return scatter;
        }

        // 训练模型
        public void Train(double[][] data1, double[][] data2)
        {
            double[] mean1 = ComputeMean(data1);
            double[] mean2 = ComputeMean(data2);

            double[,] scatter1 = ComputeWithinClassScatter(data1, mean1);
            double[,] scatter2 = ComputeWithinClassScatter(data2, mean2);

            int numFeatures = data1[0].Length;
            double[,] withinClassScatter = new double[numFeatures, numFeatures];
            for (int i = 0; i < numFeatures; i++)
            {
                for (int j = 0; j < numFeatures; j++)
                {
                    withinClassScatter[i, j] = scatter1[i, j] + scatter2[i, j];
                }
            }

            double[,] betweenClassScatter = ComputeBetweenClassScatter(mean1, mean2);

            // 计算权重向量
            weights = new double[numFeatures];
            for (int i = 0; i < numFeatures; i++)
            {
                for (int j = 0; j < numFeatures; j++)
                {
                    weights[i] += withinClassScatter[i, j] * (mean1[j] - mean2[j]);
                }
            }

            // 计算偏置项
            double mean1Projection = 0.0;
            double mean2Projection = 0.0;
            for (int i = 0; i < numFeatures; i++)
            {
                mean1Projection += weights[i] * mean1[i];
                mean2Projection += weights[i] * mean2[i];
            }
            bias = -0.5 * (mean1Projection + mean2Projection);
        }

        // 预测
        public int Predict(double[] features)
        {
            double projection = 0.0;
            for (int i = 0; i < features.Length; i++)
            {
                projection += weights[i] * features[i];
            }
            projection += bias;

            return projection > 0 ? 1 : 0;
        }
    }

    // 示例程序
    public class LDAModelExample
    {
        public LDAModelExample()
        {
            // 示例数据
            double[][] data1 = new double[][]
        {
            new double[] { 1.0, 2.0 },
            new double[] { 1.1, 2.1 },
            new double[] { 1.2, 2.2 },
            new double[] { 1.3, 2.3 }
        };

            double[][] data2 = new double[][]
        {
            new double[] { 10.0, 10.0 },
            new double[] { 10.1, 10.1 },
            new double[] { 10.2, 10.2 },
            new double[] { 10.3, 10.3 }
        };

            // 创建模型
            LDAModel model = new LDAModel();

            // 训练模型
            model.Train(data1, data2);

            // 预测
            double[] testFeatures = { 1.0, 2.0 };
            int predictedClass = model.Predict(testFeatures);

            System.Console.WriteLine("预测类别: " + predictedClass);
        }
    }
}
